package application.dao;

import application.dao.entity.Manager;
import application.dao.entity.User;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;


public class AccessDB {

    private static Logger logger = Logger.getLogger("AccessDB");
    private static Connection conn;
    private static PreparedStatement pstmt;
    private static ResultSet rs;


    /**
     * 获取连接的方法
     *
     * @return 返回一个标准的Connection连接对象
     */
    public static Connection getConnection() {
        try {
            // 加载数据库驱动
            Class.forName(DBVars.DRIVER_NAME);
            conn = DriverManager.getConnection(DBVars.URL, DBVars.USER, DBVars.PASSWORD);// 创建数据库连接
            if (conn != null) { // 如果Connection实例不为空
                System.out.println("数据库连接成功"); // 提示信息
            }
        } catch (Exception ex) {
            System.out.println("ERROR: " + ex.getMessage());
        }
        return conn;
    }

    /**
     * 关闭资源的方法
     *
     * @param conn  连接对象
     * @param pstmt sql语句执行对象
     * @param rs    结果集对象
     */
    public static void close(Connection conn, Statement pstmt, ResultSet rs) {
        try {
            if (conn != null) {
                conn.close();
            }
            if (pstmt != null) {
                pstmt.close();
            }
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 无参数的查询方法
     *
     * @param sql
     * @param cl
     * @return
     */
    public static <T> List<T> queryList(String sql, Class<T> cl) {
        return queryList(sql, cl, null);
    }

    /**
     * 查询的方法         要求用户查询的类的属性名字和  数据库表中的字段名字保持一致
     *
     * @param sql    查询语句
     * @param cl     list集合中保存的对象类型
     * @param params 参数数组
     * @return list集合结果集
     */
    public static <T> List<T> queryList(String sql, Class<T> cl, Object[] params) {
        List<T> list = new ArrayList<T>();
        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            if (params != null) {
                for (int i = 0; i < params.length; i++) {
                    pstmt.setObject(i + 1, params[i]);
                }
            }
            rs = pstmt.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            //属性的名字和 查询的列明保持一致
            while (rs.next()) {
                //通过反射机制获取一个对象
                Object obj = cl.newInstance();
                if (obj instanceof Map) {
                    MapObj(obj, rsmd, rs);
                } else {
                    for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                        //将列的名字获取到--是别名
                        String columnName = rsmd.getColumnLabel(i);

                        //根据列的名字获取到属性对象
                        Field f = cl.getDeclaredField(columnName);
                        f.setAccessible(true);
                        try {
                            f.set(obj, rs.getObject(i));
                        } catch (IllegalArgumentException ie) {
                            logger.severe("请注意你查询的数据库字段的类型也必须要和实体类中的属性类型保持一致,否则有一个字段没有数据");
                            logger.severe(ie.getMessage());
                        }
                    }
                }
                list.add((T) obj);
            }
        } catch (SQLException e) {

            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchFieldException e) {

            e.printStackTrace();
        } finally {
            close(conn, pstmt, rs);
            ;
        }
        return list;
    }


    /**
     * 增删改的方法
     *
     * @param sql
     * @param objs
     * @return 受影响的数量
     */
    public static int update(String sql, Object... objs) {

        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            if (objs != null) {
                for (int i = 0; i < objs.length; i++) {
                    pstmt.setObject(i + 1, objs[i]);
                }
            }
            return pstmt.executeUpdate();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            close(conn, pstmt, rs);
            ;
        }
        return 0;
    }


    /**
     * 从数据库中查询单条记录-如果传入的而是HashMap集合，则返回一个Map对象
     *
     * @param sql
     * @param objclass
     * @param params
     * @return 查询的结果对象 ，对象类型由objecclass指定
     */
    public static <T> T queryOne(String sql, Class<T> objclass, Object... params) {
        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            if (params != null) {
                for (int i = 0; i < params.length; i++) {
                    pstmt.setObject(i + 1, params[i]);
                }
            }
            rs = pstmt.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();
            //属性的名字和 查询的列明保持一致
            if (rs.next()) {
                //通过反射机制获取一个对象
                T obj = objclass.newInstance();
                if (obj instanceof Map) {
                    MapObj(obj, rsmd, rs);
                } else {
                    for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                        //将列的名字获取到
                        String columnName = rsmd.getColumnLabel(i);
                        //根据列的名字获取到属性对象
                        Field f = objclass.getDeclaredField(columnName);
                        f.setAccessible(true);
                        try {
                            f.set(obj, rs.getObject(i));
                        } catch (IllegalArgumentException ie) {
                            logger.severe("请注意你查询的数据库字段的类型也必须要和实体类中的属性类型保持一致,否则有一个字段没有数据");
                            logger.severe(ie.getMessage());
                        }
                    }
                }
                return obj;
            }
        } catch (SQLException e) {

            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            System.out.println("aa");
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            logger.severe("请注意你查询的数据库字段的名字是否和你实体类中的名字保持一致,否则有一个字段没有数据");
            e.printStackTrace();
        } finally {
            close(conn, pstmt, rs);
            ;
        }
        return null;
    }


    /**
     * 从数据库中查询单条记录-如果传入的而是HashMap集合，则返回一个Map对象
     *
     * @param sql
     * @param objclass
     * @return 单个结果对象
     */
    public static <T> T queryOne(String sql, Class<T> objclass) {
        return queryOne(sql, objclass, null);
    }


    /**
     * 处理map集合的方法
     *
     * @param obj
     * @param rsmd
     * @param rs
     */
    private static void MapObj(Object obj, ResultSetMetaData rsmd, ResultSet rs) {
        try {
            for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                //获取到列的名字
                String columnName = rsmd.getColumnLabel(i);
                Method method = obj.getClass().getMethod("put", Object.class, Object.class);
                method.invoke(obj, columnName, rs.getObject(i));
            }
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}